# id函数可以查看内容id
# 添加断点后可进行逐行调试，调试按钮是左上角的小虫子
# 使代码整行移动则按住alt+shift，然后再去按上下箭头就可以实现上下移动
# pass语句只是一个占位符，当没想出来具体代码内容的时候负责填充，比如
'''if answer=='y'
      pass        '''

# 输入到指定位置，使用A=open('位置处文件','a+')，而且每行代码要输入到这个位置都要在括号内最后加上file=A

# 常犯的错误：1.漏了：
# 2.缩进错误
# 3.没定义变量
# 4.==比较运算符和=赋值运算符的区别

A = open('D:/A.text', 'a+')
'''=前边是被创建的文件对象，后面是open创建文件对象的函数，括号里第一个字符串是要创建或打开的文件名称        xxx=open('filename'[,mode,encoding])
第二个字符串内容：打开读取使用r，有就写入无就创建并写入是a+'''



print(id(5), id(5), file=A)  # id函数可以查看内容id

# 转义字符
print(int('10') + int('9'), 'b\nb', file=A)  # +连接int类型则是相加，连接str类型则是直接相连，\n换行,只能在str里用
print('sha\t', file=A)  # \t是空四个制表位的意思
print('阿oo\r达', file=A)  # r是enter键
print('1234566\b11', file=A)  # \b是退一格键
print('/\\', file=A)  # 想要输出\时，必须打出来两个才能输出来一个
print(True + False, file=A)  # 布尔类型字符，只有这两种，值分别是1和0
print(R'555\n666', r'44\n44', file=A)  # 在字符串外面前面加上R或者r就可以使字符串里面的转移字符成为普通字

# 进制与字符编码
print(ord('是'), file=A)  # ord函数用来把字转化为十进制数字

# 小数精确运算时必须使用的一行代码
from decimal import Decimal

print(Decimal('0.55') + Decimal('1.11'), file=A)  # 然后在这里的小数运算的数字串前面加上Decimal就可以了

# dasgsdf    这三行展示了注释的两种方式
'''ddddd    一种是使用#可以实现单行注释
dddd'''  # 一种是使用''''''进行可换行注释

# input函数是表示提问，相当于把回答内容当作了函数的结果
# input函数得到的结果都是str类型，如果需要使用则必须转换一下
print(input('你是什么牛马'), file=A)  # 这里外包了print所以回答结果将会被输出
n1 = input('输入一个数')  # 这里则是展示了input函数可以配合其他函数使用
n2 = input('输入另一个')  # 使结果进行按定好的规则运算
print(int(n1) + int(n2))

# 算式运算符，赋值运算符，比较运算符,布尔运算符,位运算符
# 运算优先级：括号＞（幂运算符＞）算术运算符＞位运算符＞比较运算符＞布尔运算符＞赋值运算符
a = 2
b = 1
print('a=2,b=1', file=A)
print(a ** b, a % b, file=A)  # +，-，*，/，%，**，//是算式运算符(整除，取余等需要遵循规则)

print(a, b, file=A)
a += 10  # 这两个都属于赋值运算符，赋值运算符有=，+=，-=，/=,//=,%=等等，这一行所表示的就相当于a=a+10
b -= 1  # 同理，这一行就相当于b=b-1
print(a, b, file=A)  # 另外，因为这是赋值运算，所以不能被输出，这并不是一个结果，而是一种运算

print(a < b, a != b, a == b, a is not b,
      file=A)  # 比较运算符有<,>,<=,>=,!=,==, is , is not ,前六个是对值的比较，后两个是对对象id的比较，比较运算符输出的结果是布尔，即正确或者不正确

print(a < b and a != b, a < b or a != b, not a !=  b, '4' in '456', 'w' not in 'wolid',
      file=A)  # 布尔运算符中and,or,not分别对应交并补，

print(8 & 4, 8 | 4, 4 << 1, 4 >> 1, file=A)  # 位运算符一共四种，均是二进制运算，&表示前和后对应数位都是1才输出为1，否则为0，|则相反，左移运算符相当于前面的数乘2^后面那个数，|则是除

# 程序的组织结构：顺序结构，选择结构：分支结构,if嵌套,条件表达式
s = input('你是牛马吗')
if s == '是':
    print('谢谢牛马')
elif s == '不是':
    z = input('请问你想成为牛马吗')
    if z == '想':
        print('希望你早日成为牛马')
    else:
        print('回答错误')
else:
    print('回答错误')
print('谢谢牛马' if s == '是' else '回答错误')
# False,0,None,空字符串,空列表、元组、字典、集合等的布尔值均为False,其余均为True
'''所以选择结构可以这么写:
age=int(input('输入您的年龄'))
if age:
       print(age)
else:
      print('年龄为:',age)'''

# 循环：range()函数，while函数（这种必须让参数有初始值），for  in   函数可用来控制循环次数
print(range(5), range(1, 5), range(1, 8, 2), list(range(1, 8, 2)), file=A)

q = int(input('请输入一个数字'))
f = 0
while q <= 12:
    q += 1
    f += q
    print(q, file=A)
print(f, file=A)
# 用两种循环求1到100之间的偶数和
a = 0
s = 0
while a < 100:
    a += 1
    if a % 2 == 0:
        s += a
print(s, file=A)
s = 0
for a in range(1, 101):
    if a % 2 == 0:
        s += a
print(s, file=A)
# 求水仙花数
for a in range(100, 1000):  # 这个for in 循环可以把一个数的个位，十位，百位分别写出来
    ge = a % 10
    shi = a // 10 % 10
    bai = a // 100
    if ge ** 3 + shi ** 3 + bai ** 3 == a:
        print(a, file=A)
# 流程控制语句：break用于结束循环，continue用于立马结束当前的然后进入下一次循环，两者一般都与if进行搭配使用
for a in range(3):
    mm = input('请输入密码')
    if mm == '666':
        print('密码正确')
        break
    else:
        print('密码错误，请重新输入')
a = 0
while a < 3:
    mm = input('请输入密码')
    if mm == '666':
        print('密码正确')
        break
    else:
        print('密码错误，请重新输入')
    a += 1
for a in range(1, 51):
    if a % 5 != 0:
        continue
    print(a, file=A)
# else在与while和for in循环结合使用时表示正常执行完所有循环次数且没有触发break之后执行else
# break和contiue在二重循环中表示对当前所处内循环的作用，并不结束大循环
for i in range(5):
    for j in range(1, 11):
        if j % 2 == 0:
            break
        print(j, file=A)
for i in range(5):
    for j in range(1, 11):
        if j % 2 == 0:
            continue
        print(j, file=A)

# 列表：1.创建与删除，2.列表的查询操作，3.列表元素的增删改操作，4.排序，5.推导式
# 创建有两种方式，一种是使用中括号，一种是使用内置函数list
a = ['牛马', '杀马特', 98]
b = list(['牛马', 98])
# 每个元素对应唯一索引，从前往后是从0开始，从后往前是从-1开始,指定索引不存在则返回lndexError
print(a[0], a[-2], file=A)
# 获取列表中某元素的索引，如果存在相同元素，则只会返回第一个的索引，如果不存在，则会输出ValueError
print(a.index('杀马特'), file=A)
# 还可以在指定的范围内进行查找
print(a.index('牛马', 0, 3), file=A)
# 获取多个元素，使用切片操作，步长为正和步长为负两种情况
# 步长为正
print(a[0:2:2], file=A)
# 步长为负
print(a[2:0:-2], file=A)
# 判断指定元素在列表中是否存在使用in , not in
print('牛马' in a, 98 not in a, file=A)
# 列表元素的遍历，使用for 迭代变量 in 列表名 ：
for c in a:
    print(c, file=A)
# 列表元素的增删改操作
# 增 append()在列表末尾增加一个，extend()在列表的末尾至少添加一个元素，insert()在列表的任意位置添加一个元素，切片 在列表的任意位置添加至少一个元素
a.append('社会人')
a.extend(b)  # 可以直接添加一个列表进去
a.insert(2, 'giegie')
a[3:] = b  # 切片就是把那一部分切掉替换为等号后边的

# 删 remove pop 切片 clear del
a.remove('牛马')  # 溢出一个元素，如果有重复的，删除第一个，如果不存在，会提示
a.pop(0)  # 根据索引移除元素，移除不存在的的则会提示
a.pop()  # 如果不指定，则会移除最后一个元素
a[0:1] = []  # 切片其实就是把内容换成空的
a.clear()  # 清空列表内容
del a  # 直接删除这个列表对象

# 改
b[0] = '杀马特'  # 为指定索引的元素赋予一个新值
b[0:1] = [666, 555, '傻逼杀马特']  # 为指定的切片赋予一个新值

# 列表的排序 sort和内置函数sorted
c = [100, 900, 500, 400]
c.sort()  # 并不会产生新的列表对象
c.sort(reverse=True)  # 在括号里填入reverse=True即可进行降序排序
newc = sorted(c)  # 将会产生新的列表对象
newc = sorted(c, reverse=True)  # 同上上

# 列表生成式：列表名=[元素表达式 for 自定义变量 in range(数字,数字，数字)]
c = [w for w in range(0, 28, 3)]
print(c, file=A)
c = [w + 1 for w in range(0, 28, 3)]
print(c, file=A)

# 字典的原理，创建与删除，查询操作，增删改操作，推导式
# 创建：花括号或者内置函数dict()
a = {'杀马特': 250, '满伍': 360}  # 使用花括号创建，杀马特，满伍是键，250，360是值
b = dict(杀马特=250, 果郡王=360)  # 使用等号赋值，左侧不用加引号，右侧加不加看什么数据类型，等号左侧是键，右侧是值
c = {}  # 还可以创建空字典
# 获取的两种方式
print(a['杀马特'])  # 如果查找不存在，会报错
print(a.get('杀马特'))  # 如果查找不存在，默认返回None
print(a.get('掉个', 666))  # 也可以以这种形式规定如果查找不存在让其返回什么
# 增删改
print('杀马特' in a, '社会人' not in a)  # 键的判断
del a['满伍']  # 删除指定元素的键值对
a.clear()  # 清空
a['社会人'] = 666  # 增加元素
a['社会人'] = 888  # 修改
# 字典的视图操作
print(a.keys(), a.values(), a.items())  # 查看所有键，值
print(list(a.keys()), list(a.values()), list(a.items()))  # 可以把这些东西加list变成列表，列表中的元素由元组组成
# 遍历
for q in a:
    print(q, a[q], a.get(q))
# 字典的特点：key必须是不可变对象，且不可以重复，重复的话将会覆盖掉，值能重复
# 元素是无序的，字典可以根据需要进行动态的伸缩，字典会浪费比较大的内存，是一种使用空间换时间的数据结构
# 字典生成式：
# {键表达式 : 值表达式 for 自定义键的变量,自定义值的变量 in zip(键的可迭代对象，值的可迭代对象)}
keys = ['a', 'b', 'c']
va = [1, 2, 3]
d = {ke: v for ke, v in zip(keys, va)}  # 如果两个列表内元素不对等，则会以少的哪个为基准进行创建
print(d, file=A)

# 程序当中尽量使用不可变序列
# 元组，不可变序列，没有增删改操作（字符串也是不可变序列）、
# 元组中那些本身不可变的是无法改变的，但是那些本身是可变量的，可以变其内在数据，比如元组中有一个列表，那么快你可以改变列表里面的东西
# 创建,直接使用小括号或者内置函数tuple
a = ('杀马特', '叼哥', 95)  # 直接小括号
a = '杀马特', '叼哥', 95  # 也可省略小括号
tuple(('杀马特', '叼哥', 95))
b = ('杀马特',)  # 必须加小括号并且还有一个逗号
# 空元组
c = ()
d = tuple()
# 遍历，元组是可迭代对象，用 for in 进行遍历
print(a[1], file=A)
for g in a:
    print(g, file=A)
# 没有元组生成式


# 集合，可变序列，没有值，内元素不能重复，元素无序，所以输出的时候也不会是像写的时候的顺序
# 创建，直接{}或者使用内置函数set()
a = {2, 3, 6, 9, 8}
# 可以把其他序列通过函数转化为集合
b = set(range(6))
set([3, 4, 53, 56])
set('Python')
set({124, 3, 44})
set()
# 判断，增删改
print(2 in a, 6 not in a)  # 判断
a.add(50)  # 增一
a.update({666})  # 这种可以至少添加一个元素，但是在函数括号内必须再加一种序列的括号
a.remove(666)  # 删除一个指定元素
a.discard(50)  # 同上
a.pop()  # 随机删除一个元素
a.clear()  # 清空集合
# 集合之间的关系
print(a == b, a != b)  # 相等
print(a.issubset(b))  # a是否为b的子集
print(a.issuperset(b))  # a是否为b的超集
print(a.isdisjoint(b))  # a和b是否有交集
# 集合之间的操作
print(a.intersection(b))  # 求交集
print(a & b)  # 同上

print(a.union(b))  # 求并集
print(a | b)  # 同上

print(a.difference(b))  # 差集，a有但是b没有的
print(a - b)  # 同上

print(a.symmetric_difference(b))  # a和b的对称差集
print(a ^ b)  # 同上

# 集合生成式：集合名={元素表达式 for 自定义变量 in range(数字,数字，数字)}
c = {w for w in range(0, 28, 3)}
print(c, file=A)
c = {w + 1 for w in range(0, 28, 3)}
print(c, file=A)

# 总结
#  数据结构      是否可变      是否重复     是否有序     定义符号
# 列表(list)      可变        可重复       有序         []
# 元组(tuple)    不可变        可重复      有序         ()

#                          key不可重复
# 字典(dict)      可变                    无序      {key：value}
#                          value可重复

# 集合(set)       可变        不可重复      无序         {}

# 字符串怕（索引从0算起）
a = '傻逼杀马特真几把傻逼'
print(a.index('傻逼'))  # 查找子串第一次出现的位置，如果不错在，抛出ValueError
print(a.find('傻逼'))  # 同上，但是如果不存在，返回-1

print(a.rindex('傻逼'))  # 查找最后一次出现的位置
print(a.rfind('傻逼'))
# 字符串字母大小写转换方法（将产生新的字符串对象）
a = 'AccEr'
print(a.upper())  # 全体大写
print(a.lower())  # 全体小写
print(a.swapcase())  # 大小写反转
print(a.capitalize())  # 第一个字母大写，其余小写
a = 'AccEr,shabi'
print(a.title())  # 所有单词第一个字母大写，其余小写
# 字符串内容对齐操作
print(a.center(19, 'a'))  # 第一个参数控制宽度，第二个参数决定填充内容，一般默认空格
print(a.ljust(15))  # 左对齐，同上
print(a.rjust(15))  # 右对齐，同上
print(a.zfill(15))  # 右对齐，只接受一个参数，左边自动用0填充
# 字符串的劈分操作（返回的值都是一个列表）
a = 'Acc,Er,sha,abi'
print(a.split())  # 从左边开始劈分，默认按空格来劈
print(a.split(sep=','))  # 可以使用sep= 规定按什么来劈分
print(a.split(sep=',', maxsplit=2))  # 可以再加上maxsplit= 来规定最大劈分次数，其余的不再劈做一部分
print(a.rsplit())  # 从左开始劈分，但是从左从右的区别只有把sep= 和maxsplit= 都加上的时候才有
# 字符串的判断操作
print(a.isidentifier())  # 是不是合法的标识符
print(a.isspace())  # 是否全部由空白字符组成（回车，换行，水平制表符）
print(a.isalpha())  # 是否全部由字母组成
print(a.isdecimal())  # 是否全部由十进制数字组成
print(a.isnumeric())  # 是否全部由数字组成
print(a.isalnum())  # 是否全部由数字和字母组成
# 字符串的替换与合并
print(a.replace('a', 'c', 1))  # 第一个参数是被替换掉的，第二个是替换后改为的，第三个决定最大次数
a = ('aa', 'bb')
print(''.join(a))  # 可以把一个元组或者列表中的字符串合成一个字符串，.前面的字符决定合并时在中间添加什么
print('/'.join('傻杀马特真几把傻逼'))  # 还可以这样史每个中间添加一个东西
# 字符串的比较操作，在比较时，时一个一个字符比较，相等则下一个，直到不同的一个出现，这个就是比较结果，后续不再比较
# ord()和chr()是转换值与字符的对应函数
# 比较符可以用：>,>=,<,<=,==,!=

# 字符串的切片操作，和列表相同
a = '果郡王'
print(a[0:2:1])
# 格式化字符串的三种方法
# 第一种，使用%占位符，%s代表字符串，%i或者%d代表整数，%f代表浮点数
a = '杀马特'
b = 6
print('我叫%s,今年%d岁' % (a, b))
# 关卡与这个的其他用法
print('%10d' % 99)  # 那个10代表在99前面空几个位置
print('%10.3f' % 3.1415926)  # 这个.3代表保留三位小数，10就代表总长度为10
# 第二种{}方法
print('我叫{0},今年{1}岁'.format(a, b))
# 第三种方法
print(f'我叫{a},今年{b}岁')

# 字符串的编码与解码
a = '杀马特是傻逼'
print(a.encode(encoding='GBK'))  # GBK编码格式中一个中文两个字节
print(a.encode(encoding='UTF-8'))  # 在UTF-8编码格式中，一个中文占三个字节
# 解码
b = a.encode(encoding='GBK')
print(b.decode(encoding='GBK'))  # 用什么编辑格式编码就要用什么解码方式


# 函数
# 函数的创建：def 函数名（输入参数）:
#              函数体
#              [return xxx]
# 比如
# 位置实参
def love(a, b):
    l = a + a + b
    return l


print(love(4, 5))

# 将序列中的每个元素都转化为位置实参
lst = [11, 22]
print(love(*lst))

# 关键字实参
print(love(b=5, a=4))
'''函数的返回值
 1.如果没有返回值，则return可以省略不写
 2.函数的返回值如果是一个，直接返回类型
 3.如果是多个，返回元组'''
# 将字典中的每个键值都转化为关键字实参
a = {'a': 250, 'b': 360}  # 必须保持字典中的键与函数得到参数名相同
print(love(**a))


# 默认值形参
def love(a=666, b=666):  # 默认值形参不能a,b=88这样写
    l = a + a + b
    return l


print(love())
print(love(100))
print(love(100, 600))


# 关键字形参
def fun(a, b, c, d):
    print(a, b, c, d)


# 可以使用位置实参传递，关键字实参传递，两者混用也可以

# 个数可变的位置形参
def love(*args):
    print(args)  # 使用*可以使之可变，位置参数


love(44, 666, 777)  # 结果是一个元组


# 个数可变的关键字形参
def love(**args):
    print(args)  # 使用**可以使之可变，关键字形参


love(a=10, b=50, c=666)  # 结果是字典


# 全局变量和局部变量
# def love(a,b):
#    l=a+a+b       #此处的l就是局部变量，可以使用global来声明其为全局变量
#    return l
def abc(a=10, b=20):
    global l  # 如这里所示，就是这样使之成为全局变量
    l = a + b
    print(l)


abc()
print(l)


# 递归函数：在函数体内调用了函数本身。
# 组成有递归调用和递归终止条件
# 利用递归函数算阶乘
def jiecheng(n):
    if n == 1:
        return 1
    else:
        return n * jiecheng(n - 1)


print(jiecheng(6))


# 斐波那契数列
def shulie(n):
    if n == 1:
        return 1
    elif n < 1:
        return 0
    else:
        return shulie(n - 1) + shulie(n - 2)


print(shulie(6))  # 答案是8


# Python的异常处理机制：try...except...else...finally结构，最少使用前两个
# try:
#    可能会出现异常的代码
#    可能会出现异常的代码
# except 异常类型2:               #如果写  except:
#    异常处理代码                             traceback.print_exe()
#    异常处理代码                  #意思则是打印异常信息，后续可作为日志使用
# except 异常类型1:
#    异常处理代码
#    异常处理代码
# except BaseException:        #这个是最大的错误类型
#    异常处理代码
#    异常处理代码
# else:
#   代码代码                   # 如果try板块没有出现问题则执行else板块）
# finally:
#    代码代码                   #finally块无论是否发生异常都会被执行


# Python常见的异常类型
# 1 ZeroDivisionError  除（或取模）零
# 2 lndexError         序列中没有此索引
# 3 KeyErrorError      映射中没有这个键
# 4 NameError          未声明/初始化对象
# 5 SyntaxError        Python语法错误
# 6 ValueError         传入无效的参数


# 类的组成：类属性，实例方法，静态方法，类方法
# 类之外是函数，类里定义就叫方法，可以使用类名直接访问
# 类里的变量定义就是类属性
class Baa:  # (类名可以由一个或者多个单词组成，但是每个单词必须首字母大写，其余小写)
    # 类属性，被该类的所有对象所共享
    leishuxing = '吉林'  # 可以在类外进行改变

    # 初始化方法
    def __init__(self, name, age):
        self.name = name  # self.name称为实体属性，此操作是把局部变量赋给了实体属性
        self.age = age  # self.age同上

    # 实例方法
    def shili(self):
        print('我是实例函数')

    # 静态方法：必须使用下面这个修饰，而且括号里不能填东西
    @staticmethod
    def jingtai():
        print('我使用了@staticmethod修饰，所以我是静态方法')

    # 类方法
    @classmethod
    def lei(cls):
        print('我是类方法，因为我使用了classmethod进行修饰')


# 对象的创建，又称为类的实例化。实例名=类名(),因为叫实例，所以就要填充内容了
# 有了实例，就可以调用类中的内容
dx = Baa('杀马特', 20)
print(dx.name, dx.age)

# 类属性，类方法，静态方法，实例方法的使用方式
Baa.leishuxing = '河南'  # 在类外这样修改类属性
dx.shili()  # 这两个功能一样
Baa.shili(dx)  # 都是调用shili方法
Baa.jingtai()  # 调用静态方法
Baa.lei()  # 调用类方法

# 在类写成后，仍然可以动态绑定属性和方法
# 动态属性的绑定
dx.xshx = '我是新属性'
print(dx.name, dx.age, dx.xshx)


# 动态绑定方法
# 先创建一个函数
def xff():
    print('我是一个新方法')


# 然后如同绑定动态属性一样就行了
dx.xff = xff()
dx.xff


# 封装：提高程序的安全性
# 如果不希望属性在类外被访问，则在类里时全部在其前加上__
class Caa:  # (类名可以由一个或者多个单词组成，但是每个单词必须首字母大写，其余小写)
    # 类属性，被该类的所有对象所共享
    shuxing = '吉林'  # 可以在类外进行改变

    # 初始化方法
    def __init__(self, name, age):
        self.name = name  # self.name称为实体属性，此操作是把局部变量赋给了实体属性
        self.__age = age  # self.age同上

    # 实例方法
    def shili(self):
        print(self.name, self.__age)


de = Caa('aa', 41)
print(de.name)
# print(de.age)     #如果有了这两句，程序将会报错，因为age是不希望被使用的
# print(de.__age)   #如果有了这两句，程序将会报错，因为age是不希望被使用的

# 但是，也是有方法进行调用的
# 先是检索出来调用名，使用内置函数dir,里面填对象名
print(dir(de))
# 然后再调用就行了
print(de._Caa__age)

# 继承
''''#如果一个类没有写继承任何类，就是默认继承object
#Python支持多继承
#定义子类时，必须在其构造函数中调用父类的构造函数'''


# 继承有两个关键点，一个是需要把父类放入子类名后的括号内,一个是调用super方法进行属性继承
class zilei1(Baa):  # 点一
    def __init__(self, name, age, xin1):
        super().__init__(name, age)  # 点二
        self.xin1 = xin1  # 这里正常给新增加的属性实体化即可


'''方法重写
如果子类对继承子自父类的某个属性或方法不满意，可以在子类中对其进行重写
子类重写后的方法可以通过super.().xxx()调用父类中被重写的方法'''


# 为了演示可以多继承，写了两个类
class zilei2(Baa):  # 点一
    def __init__(self, name, age, xin2):
        super().__init__(name, age)  # 点二
        self.xin2 = xin2  # 这里正常给新增加的属性实体化即可

    # 调用上面的父类的方法
    def shili(self):
        super().shili()  # 调用父类的方法必须加上这个
        print('更改后的', self.name)


'''object类有一个_str_()方法，用于返回一个对于对象的描述
内置函数dir()可以查看指定对象所有属性
对应于内置函数str()经常用于print()方法，所以我们经常会对_str_()进行重写'''


class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return '我的名字是{0}，今年{1}岁'.format(self.name, self.age)


stu = Student('张三', 50)
print(dir(stu))
print(stu)  # 因为重写了__str__所以，输出时直接返回__str__方法的内容

'''多态的实现，1.首先需要写一个父类，再写几个不同的子类进行继承，
先在父类中写入一个xxx的方法，再在子类中都写入一个同样叫xxx的方法，内容随意，
然后再在最后定义一个函数，进行对xxx的调用，
如此之后，函数使用时，会根据输入的参数不同调用不同类里对应的方法'''


class py:  # 1.写父类
    def xp(self):
        print('我的朋友都有独特的性癖')


class qjw(py):  # 2.每个子类都继承，都写这个方法
    def xp(self):
        print('我全晋玮的xp是受不鸟了')


class lwq(py):
    def xp(self):
        print('我喜欢元神')


def diaoyong(py):  # 3.在这里定义一个函数，随便叫什么，
    py.xp()  # 但是必须定义为  变量.xxx()


diaoyong(qjw())  # 然后在这里调用函数时必须在变量后加上()

'''特殊属性'''


class F:
    pass


class B:
    pass


class C(B, F):
    def __init__(self, name, age):
        self.name = name
        self.age = age


class D(F):
    pass


a = C('abc', 50)
print(a.__dict__)  # 会把对应的进行字典绑定
print(C.__dict__)  # 输出其所有数据

print(a.__class__)  # 输出其对象所属的类
print(C.__bases__)  # 输出C类的父类，而且是哪个先继承哪个先输出
print(C.__base__)  # 输出C类先继承的那个父类
print(C.__mro__)  # 类的继承层次结构
print(F.__subclasses__())  # 写出其所有子类
'''特殊方法，后两个均用于创建对象的'''


# 1.   __add__   是为了实现两个对象的相加，如果不这样写，就会报错
class suibian:
    def __init__(self, name):
        self.name = name

    def __add__(self, other):  # 对应add函数
        return self.name + other.name

    def __len__(self, other):  # 对应len函数
        return len(self.name)


sb1 = suibian('张三')
sb2 = suibian('李四')
s = sb1 + sb2
print(s)
# 2.   __len__   是为了计算内容函数的长度，也是必须这样
print(len(s))


# 3.重要的  __new__  方法用于创建对象
# 4.  __init__  方法用于初始化对象
class Person():
    def __new__(cls, *args, **kwargs):
        print('__new__被调用执行了，cls的id值为{0}'.format(id(cls)))
        obj = super().__new__(cls)
        return obj

    def __init__(self, name, age):
        print('__init__被调用了，self的id值为{0}'.format(id(self)))
        self.name = name
        self.age = age


print('object这个类对象的id为:{0}'.format(id(object)))
print('Person这个类对象的id为:{0}'.format(id(Person)))

# 创建Person类的实例对象
p1 = Person('张三', 20)
print('p1这个Person类的实例对象的id:{0}'.format(id(p1)))
'''1.创建的实例对象传给方法new中的cls
2.然后是用cls创建了对象obj
3.再通过return把这个对象传给self
4.最终给了p1'''

'''浅拷贝'''


class yiyiyi:
    pass


class ererer:
    pass


class sansansan:
    def __init__(self, yyy, eee):
        self.yyy = yyy
        self.eee = eee


# 1.变量的赋值
yyy1 = yiyiyi()
yyy2 = yyy1
print(yyy1)
print(yyy2)
'变量名不同，但实际指向地址是同一个'
eee = ererer()
sss = sansansan(yyy1, eee)

# 2.浅拷贝
import copy

sss2 = copy.copy(sss)
print(sss, sss.eee, sss.yyy)
print(sss2, sss2.eee, sss2.yyy)
'''结果如下，最终发现，仍然是名字不同，其余的指针其实都是指向同样地址的
<__main__.yiyiyi object at 0x000002A8619CD208>
<__main__.yiyiyi object at 0x000002A8619CD208>
<__main__.sansansan object at 0x000002A861B172E8> <__main__.ererer object at 0x000002A861A99D68> <__main__.yiyiyi object at 0x000002A8619CD208>
<__main__.sansansan object at 0x000002A861C5B320> <__main__.ererer object at 0x000002A861A99D68> <__main__.yiyiyi object at 0x000002A8619CD208>'''

'''深度拷贝'''
sss3 = copy.deepcopy(sss)
'''深度拷贝的关键就在这里，需要用这个deepcopy函数'''
print(sss, sss.eee, sss.yyy)
print(sss3, sss3.eee, sss3.yyy)
'''结果如下，对比可知，无论是名字，还是其余的，都是不同的地址，所以深度拷贝将会创建一个全新的储存
<__main__.sansansan object at 0x0000019775C82D68> <__main__.ererer object at 0x0000019775B572E8> <__main__.yiyiyi object at 0x0000019775A0D208>
<__main__.sansansan object at 0x0000019775C82C88> <__main__.ererer object at 0x0000019775CA6080> <__main__.yiyiyi object at 0x0000019775C9FF28>'''

'''


模
块
部
分



'''

'''1.创建模块
新建一个  .py  文件，名称尽量不要与自带的标准模块名称相同'''

'''2.导入模块'''
# 1.使用  import 模块名称 [as别名]
import math

'''如此便完成了导入，可以输入dir看他都有啥能用'''
print(dir(math))
# 这种情况下使用，必须这样写      math.函数名()    ，比如    math.pow()

# 2.使用 form 模块名称 import 函数/变量/类
'''用于单独导入模块的某个指定内容，函数，变量，类'''
from math import pow

# 这种情况下，直接使用就行了 比如   pow()
print(pow(2, 3))
'''如果没有导入，却也能使用，就是使用了内置函数，是不同的'''


'''3.导入自定义模块,必须标记这个你想导入的模块的文件夹为 源 根目录'''
import ceshi as ggg
print(ggg.add(1,2))



'''以主程序方式运行'''
#在每个模块的定义中都包括一个记录模块名称的变量 _name_
#程序可以检查该变量，以确定他们在哪个模块中执行
#有时候一些被导入的模块可能会在当前模块运行其程序，只需要在那个被导入的模块中不想让它运行的代码前加上main即可
def niubi(a,b):
    return a+b
if __name__ == '__main__':#直接打main即可，再把代码缩进到他的下面
    print(niubi(10,20))
'''很明显，在另一个文件中无论是单导入方法还是全体导入现在这个模块，都会执行所有代码，正是因为特们没有缩进到这个下面'''



'''包，包与目录的区别，包的导入'''
#略

'''python中常用的内置模块'''
#  sys  与python解释器及其环境操作相关的标准库
#  time 提供与事件相关的各种函数的标准库
#  os  提供了访问操作系统服务功能的标准库
#  calender  提供与日期相关的
#  urllib  用于读取来自网上（服务器）的数据标准库     爬虫：print(urllib.requst.urlopen('http://www.baidu.com').rede()) 将会访问百度并把所有返回的信息输出
#  json  用于使用JSON序列化和反序列化              这两个爬虫也用
#  re  用于在字符串中执行正则表达式匹配和替换        这两个爬虫也用
#  math  提供便准运算函数的标准库
#  decimal  用于进行精确控制运算精度,有效数位和四舍五入操作的十进制运算
#  logging  提供了灵活的记录时间，错误，警告和调试信息等日志信息的功能



'''第三方模块的安装与使用：他人开发，我们安装即可使用'''
#打开cmd输入那个东西就可以在线下载了，然后在这里就可以导入

'''
import schedule        #导入部分
import time

def job():           #执行事件部分
    print('嗨嗨害')

schedule.every(1).seconds.do(job)          #设置每隔几秒执行一次事件，但是只是设置，并不启动
        每x . 秒/分钟/单位等等 . 执行什么
while True:
    schedule.run_pending()         #使之启动，使用这个run_pending()
    time.sleep(0)#这个可以设置休眠几秒，是这个循环休眠几秒再执行
'''



'''        编码格式           '''
'''      ASCII（128字符）
           |                           （定长编码，两个字节表示一个字符）
       ISO8859-1  ----------不兼容----------Unicode
       |      |                              |
       |      |                              |
    GB2312   UTF-8   ------  UTF-8是Unicode的实现
       |      （变长编码，1-4个字节便是一个字符，英文一个字节，汉字三个字节）
      GBK
       |
    GB18030
（左边这三个兼容上面IS那个，英文一个字节，汉字两个字节，这边统称ANSI）
'''
#如果想要改变py文件的编码格式，只需要在最上面的一行写  ”#encoding=编码格式“  就行了
#如果不写的话，默认编码格式是UTF-8，不同编码会有不同的占用空间



'''常用的文件打开模式'''


'''A = open('D:/A.text', 'a+')'''
'''=前边是被创建的文件对象，后面是open创建文件对象的函数，括号里第一个字符串是要创建或打开的文件名称        xxx=open('filename'[,mode,encoding])'''

#这些只规定模式
#r  只读模式：文件指针在文件开头
#w  只写模式:不存在则创建，存在则覆盖原有内容，指针在开头
#a  追加模式：不存在则创建，存在则则在末尾追加内容，指针在文件末尾
#b  以二进制打开文件，不能单独使用，rb或者wb
#+  以读写方式打开文件，不能单独使用，a+
#
#print(A.readlines())这一行是没用的，为什么呢，因为上面的open函数的第二个字符串不是'r',不是读取

#这里展示了如何复制，因为如果单纯只有第二行的话，只是规定了模式，就用第四行的write函数表示写，写什么呢，写从xie读到的东西，因为用了一个read函数
xie=open('abc.png','rb')
du=open('copy.png','wb')
du.write(xie.read())#
du.close()
xie.close()




'''文件对象的常用方法             这个size处换成数字就行了'''
#read([size])           从文件中读取size个字节或字符的内容返回。若省略[size]则读取到文件末尾，即一次读取文件所有内容
#readline()             从文本中读取一行内容
#readlines()            把文本文件中每一行都作为独立的字符串对象，并将这些对象放入列表返回
#write('str')           将字符串内容写入文件
#writelines(lst)        将某列表内容写入文本文件，不添加换行符
#seek(offset[,whence])  把文件指针移动到新的位置(这个新位置必须是存在的，按照汉字和英文所占的字节去数)，offset表示相对于whence的位置：
#                       offset：为正往结束方向移动，为负往开始方向移动
#                       whence不同的值代表不同含义，0代表从文箭头位置计算（默认值），1代表从当前位置开始计算，2代表从文件尾开始计算
#tell                   返回文件指针的当前位置
#flush()                把缓冲区的内容写入文件，但不关闭文件,就是先写入一遍
#closr()                把缓冲区的内容写入文件，同时关闭文件，释放文件对象相关资源


'''with语句（上下文管理器），可以自动实现关闭资源释放内存'''
#举例
#1.
with open('D:/A.text','r') as ppp:
    print(ppp.read())
#2.
with open('abc.png','rb') as di:
    with open('copy2.png','wb') as dier:
        dier.write(di.read())


'''os模块'''
import os
#调用系统应用
os.system('notepad.exe')
os.system('calc.exe')
#直接调用可执行文件
os.startfile('D:\\死火\\launch.exe')

#操作目录相关函数
#getcwd()                       返回  当前的工作目录
#listdir(path)                  返回  *+指定路径下的文件和目录信息
#mkdir(path[,mode])             创建目录
#makedirs(path1/path2..[,mode]) 创建多级目录
#rmdir(path)                    删除目录
#removedirs(path1/path2...)     删除多级目录
#chdir(path)                    将path设置为当前工作目录
#abspath(path)                  用于获取文件或目录的绝对路径
#exists(path)                   用于判断文件或目录是否存在，如果存在返回True，否则false
#join(path,name)                将目录与目录或者文件名拼接起来
#splitext()                     分离文件名和扩展名
#basename(path)                 从一个目录中提取文件名
#dirname(path)                  从一个路径中提取文件路径，不包括文件文件名
#isdir(path)                    用于判断是否为路径3















A.close() #最后在这里输入这个使信息源关闭（另外就是要在结束处用这个最终才能实现输入到位置，考古）
